package cc.rengu.oltp.service.realize.impl;

import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.TxnLimitStatisMapper;
import cc.rengu.oltp.service.common.dao.impl.TxnLimitStatisMapperImpl;
import cc.rengu.oltp.service.common.entity.TxnLimitStatis;
import cc.rengu.oltp.service.common.enums.LimitAcctTypeEnum;
import cc.rengu.oltp.service.common.enums.LimitTypeEnum;
import cc.rengu.oltp.service.common.enums.TransTypeEnum;
import cc.rengu.oltp.service.model.TransLimitInfo;
import cc.rengu.oltp.service.realize.TransLimitService;
import cc.rengu.oltp.utility.util.*;
import cc.rengu.utility.log.RgLog;
import cc.rengu.utility.log.RgLogger;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 交易限额检查
 * Created by 王成 on 2020/2/6
 */
public class TransLimitServiceImpl implements TransLimitService {
    private final RgLogger rglog = RgLog.getLogger(this.getClass().getName());
    private final List<TxnLimitStatis> txnDayLimitStatisList = new ArrayList<>();
    private final List<TxnLimitStatis> txnMonthLimitStatisList = new ArrayList<>();
    private final List<TxnLimitStatis> txnLimitStatisList = new ArrayList<>();
    private final String instId;
    private final String txnNum;
    private final String corporation;

    public TransLimitServiceImpl(String instId, String txnNum, String corporation) {
        this.instId = instId;
        this.txnNum = txnNum;
        this.corporation = corporation;
    }

    @Override
    public boolean transLimitCheck(String transAmt, List<TransLimitInfo> transLimitInfoList) throws Exception {
        /*Step1：参数合法性检查 */
        if (StringUtil.isEmptyOrNull(instId) || StringUtil.isEmptyOrNull(txnNum) || StringUtil.isEmptyOrNull(transAmt) ||
                StringUtil.isEmptyOrNull(transAmt.trim()) || null == transLimitInfoList || transLimitInfoList.isEmpty()) {
            rglog.error("参数为空,instId:<{}>,txnNum:<{}>,transAmt:<{}>,transLimitInfoList:<{}>", instId, txnNum, transAmt, transLimitInfoList);
            return false;
        }
        /*Step2：获取交易限额统计信息 */
        /* Step2.1：将商户限额配置信息按照限额类型进行排序 */
        List<TransLimitInfo> txnLimitCheckInfos = transLimitInfoList.stream().sorted(Comparator.comparing(TransLimitInfo::getLimitType)).collect(Collectors.toList());
        /* Step2.2：按照限额主体去重，并根据限额主体限额统计信息 */
        String statisDay = DateUtil.getCurrentDate();
        String statisMonth = DateUtil.getCurrentDateTime("yyyyMM");
        TxnLimitStatisMapper txnLimitStatisMapper = new TxnLimitStatisMapperImpl();
        List<TransLimitInfo> txnLimitInfos = txnLimitCheckInfos.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(TransLimitInfo::getLimitInst))), ArrayList::new));
        for (TransLimitInfo txnLimitInfo : txnLimitInfos) {
            /* Step2.2.1：根据限额配置信息查询日限额统计信息 */
            List<TxnLimitStatis> txnDayLimitStatis = txnLimitStatisMapper.selectTxnLimitStatisByLimitInst(txnLimitInfo.getInstId(), statisDay, "D", txnLimitInfo.getLimitInst());
            if (null != txnDayLimitStatis && !txnDayLimitStatis.isEmpty()) {
                txnDayLimitStatisList.addAll(txnDayLimitStatis);
            }
            /* Step2.2.2：根据限额配置信息查询月限额统计信息 */
            List<TxnLimitStatis> txnMonthLimitStatis = txnLimitStatisMapper.selectTxnLimitStatisByLimitInst(txnLimitInfo.getInstId(), statisMonth, "M", txnLimitInfo.getLimitInst());
            if (null != txnMonthLimitStatis && !txnMonthLimitStatis.isEmpty()) {
                txnMonthLimitStatisList.addAll(txnMonthLimitStatis);
            }
        }
        /*Step3：交易限额检查 */
        return limitCheck(txnLimitCheckInfos, transAmt);
    }

    @Override
    public boolean transLimitStatis(String transAmt, List<TransLimitInfo> transLimitInfoList) {
        int iReturnCode = 0;
        if (StringUtil.isEmptyOrNull(instId) || StringUtil.isEmptyOrNull(txnNum) || StringUtil.isEmptyOrNull(transAmt) ||
                StringUtil.isEmptyOrNull(transAmt.trim()) || null == transLimitInfoList || transLimitInfoList.isEmpty()) {
            rglog.error("参数为空,instId:<{}>,txnNum:<{}>,transAmt:<{}>,transLimitInfoList:<{}>", instId, txnNum, transAmt, transLimitInfoList);
            return false;
        }
        String dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(AppParamConstant.DATABASE_CONF_NODE, AppParamConstant.OLTP_POOL_NAME);
        if (null != corporation && !corporation.isEmpty()) {
            String dbPoolCashNode = corporation.trim() + AppParamConstant.DATABASE_CONF_NODE;
            dbPoolName = XmlConfigUtil.getXmlConfigCacheKeyValue(dbPoolCashNode, AppParamConstant.OLTP_POOL_NAME);
        }
        DbsUtil dbsUtil = new DbsUtil(dbPoolName);
        dbsUtil.dbsBeginTransaction();
        try {
            String statisDay = DateUtil.getCurrentDate();
            String statisMonth = DateUtil.getCurrentDateTime("yyyyMM");
            TxnLimitStatisMapper txnLimitStatisMapper = new TxnLimitStatisMapperImpl();
            for (TransLimitInfo transLimitInfo : transLimitInfoList) {
                /* 日累计限额更新 */
                TxnLimitStatis txnDayLimitStatis = txnLimitStatisMapper.selectTxnLimitStatisByLimitInstAndAcctType(transLimitInfo.getInstId(), statisDay, "D", transLimitInfo.getLimitType(), transLimitInfo.getLimitInst(), transLimitInfo.getLimitAcctType());
                if (null == txnDayLimitStatis) {
                    if ((null != transLimitInfo.getDayLimitAmt() && !transLimitInfo.getDayLimitAmt().isEmpty()) || transLimitInfo.getDayLimitNum() > 0 ||
                            (null != transLimitInfo.getDayRefundLimitAmt() && !transLimitInfo.getDayRefundLimitAmt().isEmpty())) {
                        txnDayLimitStatis = initTxnLimitStatisInfo(transLimitInfo, txnNum, transAmt, "D", statisDay);
                        iReturnCode = txnLimitStatisMapper.insertTxnLimitStatis(txnDayLimitStatis);
                    }
                } else {
                    updateTxnLimitStatisInfo(txnDayLimitStatis, transLimitInfo.getLimitAcctType(), txnNum, transAmt);
                    iReturnCode = txnLimitStatisMapper.updateTxnLimitStatisByPrimaryKey(txnDayLimitStatis);
                }
                if (0 != iReturnCode) {
                    rglog.error("登记或者更新交易日累计限额统计信息<{}>失败,iReturnCode:<{}>", txnDayLimitStatis.getStaticPrimaryKey(), iReturnCode);
                    dbsUtil.dbsEndTransaction(false);
                    return false;
                }
                /* 月累计限额更新 */
                TxnLimitStatis txnMonthLimitStatis = txnLimitStatisMapper.selectTxnLimitStatisByLimitInstAndAcctType(transLimitInfo.getInstId(), statisMonth, "M", transLimitInfo.getLimitType(), transLimitInfo.getLimitInst(), transLimitInfo.getLimitAcctType());
                if (null == txnMonthLimitStatis) {
                    if ((null != transLimitInfo.getMonthLimitAmt() && !transLimitInfo.getMonthLimitAmt().isEmpty()) || transLimitInfo.getMonthLimitNum() > 0) {
                        txnMonthLimitStatis = initTxnLimitStatisInfo(transLimitInfo, txnNum, transAmt, "M", statisMonth);
                        iReturnCode = txnLimitStatisMapper.insertTxnLimitStatis(txnMonthLimitStatis);
                    }
                } else {
                    updateTxnLimitStatisInfo(txnMonthLimitStatis, transLimitInfo.getLimitAcctType(), txnNum, transAmt);
                    iReturnCode = txnLimitStatisMapper.updateTxnLimitStatisByPrimaryKey(txnMonthLimitStatis);
                }
                if (0 != iReturnCode) {
                    rglog.error("登记或者更新交易月累计限额统计信息<{}>失败,iReturnCode:<{}>", txnMonthLimitStatis.getStaticPrimaryKey(), iReturnCode);
                    dbsUtil.dbsEndTransaction(false);
                    return false;
                }
            }
            dbsUtil.dbsEndTransaction(true);
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("更新交易限额统计信息失败：{}", byteArrayOutputStream.toString());
            dbsUtil.dbsEndTransaction(false);
            return false;
        }
        return true;
    }

    @Override
    public List<TxnLimitStatis> getBankLimitStatisInfo(String mchntLevel, String mchntScope, String industryType) throws Exception {
        List<TxnLimitStatis> txnLimitStatisList = new ArrayList<>();
        /* Step1：获取商户等级限额统计信息 */
        if (null != mchntLevel) {
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, mchntLevel);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        /* Step2：获取商户组别限额统计信息 */
        if (null != mchntScope) {
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, mchntScope);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        /* Step3：获取行业类别限额统计信息 */
        if (null != industryType) {
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, industryType);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        return txnLimitStatisList;
    }

    @Override
    public List<TxnLimitStatis> getMchntLimitStatisInfo(String mchntNo, String termNo, String txnNum) throws Exception {
        List<TxnLimitStatis> txnLimitStatisList = new ArrayList<>();
        /* Step1：获取商户限额统计信息 */
        if (null != mchntNo) {
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, mchntNo);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        /* Step2：获取商户终端限额统计信息 */
        if (null != mchntNo && null != termNo) {
            String limitInst = mchntNo.trim() + "|" + termNo.trim();
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, limitInst);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        /* Step3：获取商户交易限额统计信息 */
        if (null != mchntNo && null != txnNum) {
            String limitInst = mchntNo.trim() + "|" + txnNum.trim();
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, limitInst);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        return txnLimitStatisList;
    }

    @Override
    public List<TxnLimitStatis> getChannelLimitStatisInfo(String channelId, String txnNum) throws Exception {
        List<TxnLimitStatis> txnLimitStatisList = new ArrayList<>();
        /* Step1：获取通道交易限额统计信息 */
        if (null != channelId && null != txnNum) {
            String limitInst = channelId.trim() + "|" + txnNum.trim();
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, limitInst);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        return txnLimitStatisList;
    }

    @Override
    public List<TxnLimitStatis> getAcctLimitStatisInfo(String payAcctNo) throws Exception {
        List<TxnLimitStatis> txnLimitStatisList = new ArrayList<>();
        /* Step1：获取支付账号限额统计信息 */
        if (null != payAcctNo) {
            List<TxnLimitStatis> txnLimitStatis = getTxnLimitStatisInfo(instId, payAcctNo);
            if (!txnLimitStatis.isEmpty()) {
                txnLimitStatisList.addAll(txnLimitStatis);
            }
        }
        return txnLimitStatisList;
    }

    /**
     * 交易限额检查
     *
     * @param transAmt 交易金额
     * @return ture-限额检查通过，false-限额检查超限
     */
    private boolean limitCheck(List<TransLimitInfo> txnLimitCheckInfos, String transAmt) {
        for (TransLimitInfo txnLimitInfo : txnLimitCheckInfos) {
            String statisPrimaryKey = txnLimitInfo.getLimitType() + txnLimitInfo.getLimitInst() + txnLimitInfo.getLimitAcctType();
            /* Step1：月累计限额检查 */
            if (!txnMonthLimitStatisList.isEmpty()) {
                Optional<TxnLimitStatis> txnMonthLimitStatisOpt = txnMonthLimitStatisList.stream().filter(item -> item.getStaticPrimaryKey().equals(statisPrimaryKey)).findFirst();
                if (txnMonthLimitStatisOpt.isPresent()) {
                    TxnLimitStatis txnLimitStatis = txnMonthLimitStatisOpt.get();
                    /* Step1.1：若为商户限额，判断是否同时有商户等级限额，若有，则累加等级及商户限额再进行限额检查 */
                    if (LimitTypeEnum.MCHNT_NO.getLimitType().equals(txnLimitInfo.getLimitType())) {
                        String mchntTxnLimitPrimaryKey = LimitTypeEnum.MCHNT_LEVEL.getLimitType() + txnLimitInfo.getLimitInst() + txnLimitInfo.getLimitAcctType();
                        Optional<TxnLimitStatis> mchntTxnMonthLimitStatOpt = txnMonthLimitStatisList.stream().filter(item -> item.getStaticPrimaryKey().equals(mchntTxnLimitPrimaryKey)).findFirst();
                        if (mchntTxnMonthLimitStatOpt.isPresent()) {
                            txnLimitStatis.setTotalTransAmt(AmountUtil.addition(txnLimitStatis.getTotalTransAmt(), mchntTxnMonthLimitStatOpt.get().getTotalTransAmt()));
                            txnLimitStatis.setTotalTransNum(txnLimitStatis.getTotalTransNum() + mchntTxnMonthLimitStatOpt.get().getTotalTransNum());
                            txnLimitStatis.setCreditTransAmt(AmountUtil.addition(txnLimitStatis.getCreditTransAmt(), mchntTxnMonthLimitStatOpt.get().getCreditTransAmt()));
                            txnLimitStatis.setCreditTransNum(txnLimitStatis.getCreditTransNum() + mchntTxnMonthLimitStatOpt.get().getCreditTransNum());
                            txnLimitStatis.setDebitTransAmt(AmountUtil.addition(txnLimitStatis.getDebitTransAmt(), mchntTxnMonthLimitStatOpt.get().getDebitTransAmt()));
                            txnLimitStatis.setDebitTransNum(txnLimitStatis.getDebitTransNum() + mchntTxnMonthLimitStatOpt.get().getDebitTransNum());
                            txnLimitStatis.setRefundTransAmt(AmountUtil.addition(txnLimitStatis.getRefundTransAmt(), mchntTxnMonthLimitStatOpt.get().getRefundTransAmt()));
                            txnLimitStatis.setRefundTransNum(txnLimitStatis.getRefundTransNum() + mchntTxnMonthLimitStatOpt.get().getRefundTransNum());
                        }
                    }
                    boolean limitCheckFlag = monthLimitCheck(txnLimitInfo, txnLimitStatis, transAmt);
                    if (!limitCheckFlag) {
                        rglog.error("月交易限额超限！");
                        return false;
                    }
                } else {
                    /* 存在月统计限额，但是没有当前统计类型的月累计统计信息，作为当前统计类型第1笔交易进行限额检查 */
                    String statisMonth = DateUtil.getCurrentDateTime("yyyyMM");
                    TxnLimitStatis txnLimitStatis = initTxnLimitStatisInfo(txnLimitInfo, txnNum, "0", "M", statisMonth);
                    boolean limitCheckFlag = monthLimitCheck(txnLimitInfo, txnLimitStatis, transAmt);
                    if (!limitCheckFlag) {
                        rglog.error("单笔/月交易限额超限！");
                        return false;
                    }
                }
            }
            /* Step2：日累计限额检查 */
            if (!txnDayLimitStatisList.isEmpty()) {
                Optional<TxnLimitStatis> txnDayLimitStatisOpt = txnDayLimitStatisList.stream().filter(item -> item.getStaticPrimaryKey().equals(statisPrimaryKey)).findFirst();
                if (txnDayLimitStatisOpt.isPresent()) {
                    TxnLimitStatis txnLimitStatis = txnDayLimitStatisOpt.get();
                    /* Step1.1：若为商户限额，判断是否同时有商户等级限额，若有，则累加等级及商户限额再进行限额检查 */
                    if (LimitTypeEnum.MCHNT_NO.getLimitType().equals(txnLimitInfo.getLimitType())) {
                        String mchntTxnLimitPrimaryKey = LimitTypeEnum.MCHNT_LEVEL.getLimitType() + txnLimitInfo.getLimitInst() + txnLimitInfo.getLimitAcctType();
                        Optional<TxnLimitStatis> mchntTxnMonthLimitStatOpt = txnDayLimitStatisList.stream().filter(item -> item.getStaticPrimaryKey().equals(mchntTxnLimitPrimaryKey)).findFirst();
                        if (mchntTxnMonthLimitStatOpt.isPresent()) {
                            txnLimitStatis.setTotalTransAmt(AmountUtil.addition(txnLimitStatis.getTotalTransAmt(), mchntTxnMonthLimitStatOpt.get().getTotalTransAmt()));
                            txnLimitStatis.setTotalTransNum(txnLimitStatis.getTotalTransNum() + mchntTxnMonthLimitStatOpt.get().getTotalTransNum());
                            txnLimitStatis.setCreditTransAmt(AmountUtil.addition(txnLimitStatis.getCreditTransAmt(), mchntTxnMonthLimitStatOpt.get().getCreditTransAmt()));
                            txnLimitStatis.setCreditTransNum(txnLimitStatis.getCreditTransNum() + mchntTxnMonthLimitStatOpt.get().getCreditTransNum());
                            txnLimitStatis.setDebitTransAmt(AmountUtil.addition(txnLimitStatis.getDebitTransAmt(), mchntTxnMonthLimitStatOpt.get().getDebitTransAmt()));
                            txnLimitStatis.setDebitTransNum(txnLimitStatis.getDebitTransNum() + mchntTxnMonthLimitStatOpt.get().getDebitTransNum());
                            txnLimitStatis.setRefundTransAmt(AmountUtil.addition(txnLimitStatis.getRefundTransAmt(), mchntTxnMonthLimitStatOpt.get().getRefundTransAmt()));
                            txnLimitStatis.setRefundTransNum(txnLimitStatis.getRefundTransNum() + mchntTxnMonthLimitStatOpt.get().getRefundTransNum());
                        }
                    }
                    boolean limitCheckFlag = dayLimitCheck(txnLimitInfo, txnLimitStatis, transAmt);
                    if (!limitCheckFlag) {
                        rglog.error("日交易限额超限！");
                        return false;
                    }
                } else {
                    /* 存在日统计限额，但是没有当前统计类型的日累计统计信息，作为当前统计类型第1笔交易进行限额检查 */
                    String statisDay = DateUtil.getCurrentDate();
                    TxnLimitStatis txnLimitStatis = initTxnLimitStatisInfo(txnLimitInfo, txnNum, "0", "D", statisDay);
                    boolean limitCheckFlag = dayLimitCheck(txnLimitInfo, txnLimitStatis, transAmt);
                    if (!limitCheckFlag) {
                        rglog.error("单笔/日交易限额超限！");
                        return false;
                    }
                }
            }
            /* 第1笔交易，设置交易限额累计统计的金额和笔数为0 */
            String statisDay = DateUtil.getCurrentDate();
            TxnLimitStatis txnLimitStatis = initTxnLimitStatisInfo(txnLimitInfo, txnNum, "0", "D", statisDay);
            boolean limitCheckFlag = dayLimitCheck(txnLimitInfo, txnLimitStatis, transAmt);
            if (!limitCheckFlag) {
                rglog.error("日累计交易限额超限！");
                return false;
            }
        }
        return true;
    }

    /**
     * 交易日限额检查
     *
     * @param txnLimitInfo   交易日限额配置信息
     * @param txnLimitStatis 交易日限额统计信息
     * @param transAmt       交易金额
     * @return ture-限额检查通过，false-限额检查超限
     */
    private boolean dayLimitCheck(TransLimitInfo txnLimitInfo, TxnLimitStatis txnLimitStatis, String transAmt) {
        String limitTypeDesc = LimitTypeEnum.getLimitTypeDesc(txnLimitInfo.getLimitType());
        /* Step1：支付类交易限额检查(01-支付交易及061-预授权交易) */
        if (txnNum.substring(1, 3).equals(TransTypeEnum.PAY.getTransType()) || (txnNum.substring(1, 3).equals(TransTypeEnum.AUTH.getTransType()) && "5".equals(txnNum.substring(5, 6)))) {
            /* Step1.1：单笔最小交易限额检查 */
            if (null != txnLimitInfo.getSingleLimitMinAmt() && !txnLimitInfo.getSingleLimitMinAmt().isEmpty() && AmountUtil.compare(transAmt, txnLimitInfo.getSingleLimitMinAmt()) == -1) {
                rglog.error("{}:<{}>单笔最小限额超限,配置限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getSingleLimitMinAmt(), transAmt);
                return false;
            }
            /* Step1.2：单笔最大交易限额检查 */
            if (null != txnLimitInfo.getSingleLimitMaxAmt() && !txnLimitInfo.getSingleLimitMaxAmt().isEmpty() && AmountUtil.compare(txnLimitInfo.getSingleLimitMaxAmt(), transAmt) == -1) {
                rglog.error("{}:<{}>单笔最大限额超限,配置限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getSingleLimitMaxAmt(), transAmt);
                return false;
            }
            /* Step1.3：日累计借记或者贷记限额限次检查 */
            String dayCreditDebitLimitStatisAmt = txnLimitStatis.getDebitTransAmt();
            int dayCreditDebitlimitStatisNum = txnLimitStatis.getDebitTransNum();
            if (!txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.ALL.getAcctType())) {
                if (txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                    dayCreditDebitLimitStatisAmt = txnLimitStatis.getCreditTransAmt();
                    dayCreditDebitlimitStatisNum = txnLimitStatis.getCreditTransNum();
                }
                String checkDayCreditDebitAmt = AmountUtil.addition(transAmt, dayCreditDebitLimitStatisAmt);
                if (null != txnLimitInfo.getDayLimitAmt() && !txnLimitInfo.getDayLimitAmt().isEmpty() && AmountUtil.compare(txnLimitInfo.getDayLimitAmt(), checkDayCreditDebitAmt) == -1) {
                    rglog.error("{}:<{}>{}日累计限额超限,配置限额:<{}>,已使用限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), LimitAcctTypeEnum.getAcctTypeDesc(txnLimitInfo.getLimitAcctType()), txnLimitInfo.getDayLimitAmt(), dayCreditDebitLimitStatisAmt, transAmt);
                    return false;
                }
                if (txnLimitInfo.getDayLimitNum() > 0 && txnLimitInfo.getDayLimitNum() < dayCreditDebitlimitStatisNum + 1) {
                    rglog.error("{}:<{}>{}日累计限次超限,配置限次:<{}>,已交易次数:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), LimitAcctTypeEnum.getAcctTypeDesc(txnLimitInfo.getLimitAcctType()), txnLimitInfo.getDayLimitNum(), dayCreditDebitlimitStatisNum);
                    return false;
                }
            }
            /* Step1.4：日累计交易额限额限次检查 */
            String checkDayLimitAmt = AmountUtil.addition(transAmt, txnLimitStatis.getTotalTransAmt());
            if (null != txnLimitInfo.getDayLimitAmt() && !txnLimitInfo.getDayLimitAmt().isEmpty() && AmountUtil.compare(txnLimitInfo.getDayLimitAmt(), checkDayLimitAmt) == -1) {
                rglog.error("{}:<{}>日累计限额超限,配置限额:<{}>,已使用限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getDayLimitAmt(), txnLimitStatis.getTotalTransAmt(), transAmt);
                return false;
            }
            if (txnLimitInfo.getDayLimitNum() > 0 && txnLimitInfo.getDayLimitNum() < txnLimitStatis.getTotalTransNum() + 1) {
                rglog.error("{}:<{}>日累计限次超限,配置限次:<{}>,已交易次数:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getDayLimitNum(), txnLimitStatis.getTotalTransNum());
                return false;
            }
            /* Step1.5：将交易金额更新到日累计限额中 */
            Optional<TxnLimitStatis> txnLimitStatisOpt = txnLimitStatisList.stream().filter(item -> item.getStaticPrimaryKey().equals(txnLimitStatis.getStaticPrimaryKey())).findFirst();
            if (txnLimitStatisOpt.isPresent()) {
                if (txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                    txnLimitStatisOpt.get().setCreditTransAmt(AmountUtil.addition(transAmt, dayCreditDebitLimitStatisAmt));
                    txnLimitStatisOpt.get().setCreditTransNum(dayCreditDebitlimitStatisNum + 1);
                } else {
                    txnLimitStatisOpt.get().setDebitTransAmt(AmountUtil.addition(transAmt, dayCreditDebitLimitStatisAmt));
                    txnLimitStatisOpt.get().setDebitTransNum(dayCreditDebitlimitStatisNum + 1);
                }
                txnLimitStatisOpt.get().setTotalTransAmt(checkDayLimitAmt);
                txnLimitStatisOpt.get().setTotalTransNum(txnLimitStatis.getTotalTransNum() + 1);
            } else {
                if (txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                    txnLimitStatis.setCreditTransAmt(AmountUtil.addition(transAmt, dayCreditDebitLimitStatisAmt));
                    txnLimitStatis.setCreditTransNum(dayCreditDebitlimitStatisNum + 1);
                } else {
                    txnLimitStatis.setDebitTransAmt(AmountUtil.addition(transAmt, dayCreditDebitLimitStatisAmt));
                    txnLimitStatis.setDebitTransNum(dayCreditDebitlimitStatisNum + 1);
                }
                txnLimitStatis.setTotalTransAmt(checkDayLimitAmt);
                txnLimitStatis.setTotalTransNum(txnLimitStatis.getTotalTransNum() + 1);
                txnLimitStatisList.add(txnLimitStatis);
            }
        }
        /* Step2：退款类交易限额检查(04-退款) */
        if (txnNum.substring(1, 3).equals(TransTypeEnum.REFUND.getTransType())) {
            /* Step2.1：单笔退款限额检查 */
            if (null != txnLimitInfo.getSingleRefundLimitAmt() && !txnLimitInfo.getSingleRefundLimitAmt().isEmpty() && AmountUtil.compare(txnLimitInfo.getSingleRefundLimitAmt(), transAmt) == -1) {
                rglog.error("{}:<{}>单笔退款限额超限,配置限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getSingleRefundLimitAmt(), transAmt);
                return false;
            }
            /* Step2.2：日累计退款限额检查 */
            String dayRefundCheckAmt = AmountUtil.addition(transAmt, txnLimitStatis.getRefundTransAmt());
            if (null != txnLimitInfo.getDayRefundLimitAmt() && !txnLimitInfo.getDayRefundLimitAmt().isEmpty() && AmountUtil.compare(txnLimitInfo.getDayRefundLimitAmt(), dayRefundCheckAmt) == -1) {
                rglog.error("{}:<{}>日累计退款限额超限,配置限额:<{}>,已使用限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getDayRefundLimitAmt(), txnLimitStatis.getRefundTransAmt(), transAmt);
                return false;
            }
            /* Step2.3：将交易金额更新到日累计退款限额中 */
            Optional<TxnLimitStatis> txnLimitStatisOpt = txnLimitStatisList.stream().filter(item -> item.getStaticPrimaryKey().equals(txnLimitStatis.getStaticPrimaryKey())).findFirst();
            if (txnLimitStatisOpt.isPresent()) {
                txnLimitStatisOpt.get().setRefundTransAmt(dayRefundCheckAmt);
            } else {
                txnLimitStatis.setRefundTransAmt(dayRefundCheckAmt);
                txnLimitStatisList.add(txnLimitStatis);
            }
        }
        return true;
    }

    /**
     * 交易月限额检查
     *
     * @param txnLimitInfo   交易月限额配置信息
     * @param txnLimitStatis 交易月限额统计信息
     * @param transAmt       交易金额
     * @return ture-限额检查通过，false-限额检查超限
     */
    private boolean monthLimitCheck(TransLimitInfo txnLimitInfo, TxnLimitStatis txnLimitStatis, String transAmt) {
        String limitTypeDesc = LimitTypeEnum.getLimitTypeDesc(txnLimitInfo.getLimitType());
        /* Step1：支付类交易限额检查(01-支付交易及061-预授权交易) */
        if (txnNum.substring(1, 3).equals(TransTypeEnum.PAY.getTransType()) || (txnNum.substring(1, 3).equals(TransTypeEnum.AUTH.getTransType()) && "5".equals(txnNum.substring(5, 6)))) {
            /* Step1.1：月累计借记或者贷记限额限次检查 */
            String monthCreditDebitLimitStatisAmt = txnLimitStatis.getDebitTransAmt();
            int monthCreditDebitlimitStatisNum = txnLimitStatis.getDebitTransNum();
            if (!txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.ALL.getAcctType())) {
                if (txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                    monthCreditDebitLimitStatisAmt = txnLimitStatis.getCreditTransAmt();
                    monthCreditDebitlimitStatisNum = txnLimitStatis.getCreditTransNum();
                }
                String checkMonthCreditDebitAmt = AmountUtil.addition(transAmt, monthCreditDebitLimitStatisAmt);
                if (null != txnLimitInfo.getMonthLimitAmt() && !txnLimitInfo.getMonthLimitAmt().isEmpty() && AmountUtil.compare(txnLimitInfo.getMonthLimitAmt(), checkMonthCreditDebitAmt) == -1) {
                    rglog.error("{}:<{}>{}月累计限额超限,配置限额:<{}>,已使用限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), LimitAcctTypeEnum.getAcctTypeDesc(txnLimitInfo.getLimitAcctType()), txnLimitInfo.getMonthLimitAmt(), monthCreditDebitLimitStatisAmt, transAmt);
                    return false;
                }
                if (txnLimitInfo.getMonthLimitNum() > 0 && txnLimitInfo.getMonthLimitNum() < monthCreditDebitlimitStatisNum + 1) {
                    rglog.error("{}:<{}>{}月累计限次超限,配置限次:<{}>,已交易次数:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), LimitAcctTypeEnum.getAcctTypeDesc(txnLimitInfo.getLimitAcctType()), txnLimitInfo.getMonthLimitNum(), monthCreditDebitlimitStatisNum);
                    return false;
                }
            }
            /* Step1.2：月累计交易额限额限次检查 */
            String checkMonthLimitAmt = AmountUtil.addition(transAmt, txnLimitStatis.getTotalTransAmt());
            if (null != txnLimitInfo.getMonthLimitAmt() && !txnLimitInfo.getMonthLimitAmt().isEmpty() && AmountUtil.compare(txnLimitInfo.getMonthLimitAmt(), checkMonthLimitAmt) == -1) {
                rglog.error("{}:<{}>月累计限额超限,配置限额:<{}>,已使用限额:<{}>,当前交易金额:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getMonthLimitAmt(), txnLimitStatis.getTotalTransAmt(), transAmt);
                return false;
            }
            if (txnLimitInfo.getMonthLimitNum() > 0 && txnLimitInfo.getMonthLimitNum() < txnLimitStatis.getTotalTransNum() + 1) {
                rglog.error("{}:<{}>月累计限次超限,配置限次:<{}>,已交易次数:<{}>", limitTypeDesc, txnLimitInfo.getInstId(), txnLimitInfo.getMonthLimitNum(), txnLimitStatis.getTotalTransNum());
                return false;
            }
            /* Step1.3：将交易金额更新到日累计限额中 */
            Optional<TxnLimitStatis> txnLimitStatisOpt = txnLimitStatisList.stream().filter(item -> item.getStaticPrimaryKey().equals(txnLimitStatis.getStaticPrimaryKey())).findFirst();
            if (txnLimitStatisOpt.isPresent()) {
                if (txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                    txnLimitStatisOpt.get().setCreditTransAmt(AmountUtil.addition(transAmt, monthCreditDebitLimitStatisAmt));
                    txnLimitStatisOpt.get().setCreditTransNum(monthCreditDebitlimitStatisNum + 1);
                } else {
                    txnLimitStatisOpt.get().setDebitTransAmt(AmountUtil.addition(transAmt, monthCreditDebitLimitStatisAmt));
                    txnLimitStatisOpt.get().setDebitTransNum(monthCreditDebitlimitStatisNum + 1);
                }
                txnLimitStatisOpt.get().setTotalTransAmt(checkMonthLimitAmt);
                txnLimitStatisOpt.get().setTotalTransNum(txnLimitStatis.getTotalTransNum() + 1);
            } else {
                if (txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                        txnLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                    txnLimitStatis.setCreditTransAmt(AmountUtil.addition(transAmt, monthCreditDebitLimitStatisAmt));
                    txnLimitStatis.setCreditTransNum(monthCreditDebitlimitStatisNum + 1);
                } else {
                    txnLimitStatis.setDebitTransAmt(AmountUtil.addition(transAmt, monthCreditDebitLimitStatisAmt));
                    txnLimitStatis.setDebitTransNum(monthCreditDebitlimitStatisNum + 1);
                }
                txnLimitStatis.setTotalTransAmt(checkMonthLimitAmt);
                txnLimitStatis.setTotalTransNum(txnLimitStatis.getTotalTransNum() + 1);
                txnLimitStatisList.add(txnLimitStatis);
            }
        }
        return true;
    }

    /**
     * 初始化交易限额统计信息
     *
     * @param transLimitInfo 交易限额配置信息
     * @param txnNum         交易类型
     * @param transAmt       交易金额
     * @param statisType     统计类型
     * @param statisDate     统计日期
     * @return 交易限额统计信息
     */
    private TxnLimitStatis initTxnLimitStatisInfo(TransLimitInfo transLimitInfo, String txnNum, String transAmt, String statisType, String statisDate) {
        TxnLimitStatis txnLimitStatis = new TxnLimitStatis();
        txnLimitStatis.setInstId(transLimitInfo.getInstId());
        txnLimitStatis.setStatisDate(statisDate);
        txnLimitStatis.setStatisType(statisType);
        txnLimitStatis.setStaticPrimaryKey(transLimitInfo.getLimitType().trim() + transLimitInfo.getLimitInst().trim() + transLimitInfo.getLimitAcctType().trim());
        txnLimitStatis.setLimitType(transLimitInfo.getLimitType());
        txnLimitStatis.setLimitInst(transLimitInfo.getLimitInst());
        txnLimitStatis.setLimitAcctType(transLimitInfo.getLimitAcctType());
        txnLimitStatis.setTotalTransAmt("0.00");
        txnLimitStatis.setTotalTransNum(0);
        txnLimitStatis.setCreditTransAmt("0.00");
        txnLimitStatis.setCreditTransNum(0);
        txnLimitStatis.setDebitTransAmt("0.00");
        txnLimitStatis.setDebitTransNum(0);
        txnLimitStatis.setRefundTransAmt("0.00");
        txnLimitStatis.setRefundTransNum(0);
        if (txnNum.substring(1, 3).equals(TransTypeEnum.PAY.getTransType()) || (txnNum.substring(1, 3).equals(TransTypeEnum.AUTH.getTransType()) && "5".equals(txnNum.substring(5, 6)))) {
            if (((null != transLimitInfo.getDayLimitAmt() && !transLimitInfo.getDayLimitAmt().isEmpty()) || transLimitInfo.getDayLimitNum() > 0) ||
                    ((null != transLimitInfo.getMonthLimitAmt() && !transLimitInfo.getMonthLimitAmt().isEmpty()) || transLimitInfo.getMonthLimitNum() > 0)) {
                if (transLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.ALL.getAcctType())) {
                    txnLimitStatis.setTotalTransAmt(transAmt);
                    txnLimitStatis.setTotalTransNum(("0".equals(transAmt)) ? 0 : 1);
                } else if (transLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                        transLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                        transLimitInfo.getLimitAcctType().equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                    txnLimitStatis.setTotalTransAmt(transAmt);
                    txnLimitStatis.setTotalTransNum(("0".equals(transAmt)) ? 0 : 1);
                    txnLimitStatis.setCreditTransAmt(transAmt);
                    txnLimitStatis.setCreditTransNum(("0".equals(transAmt)) ? 0 : 1);
                } else {
                    txnLimitStatis.setTotalTransAmt(transAmt);
                    txnLimitStatis.setTotalTransNum(("0".equals(transAmt)) ? 0 : 1);
                    txnLimitStatis.setDebitTransAmt(transAmt);
                    txnLimitStatis.setDebitTransNum(("0".equals(transAmt)) ? 0 : 1);
                }
            }
        } else if (txnNum.substring(1, 3).equals(TransTypeEnum.REFUND.getTransType())) {
            if (null != transLimitInfo.getDayRefundLimitAmt() && !transLimitInfo.getDayRefundLimitAmt().isEmpty()) {
                txnLimitStatis.setRefundTransAmt(transAmt);
                txnLimitStatis.setRefundTransNum(("0".equals(transAmt)) ? 0 : 1);
            }
        } else {
            rglog.info("非支付或者退款交易!");
        }
        txnLimitStatis.setCreateTime(DateUtil.getCurrentDateTime("yyyy-MM-dd HH:mm:ss.SSS"));
        return txnLimitStatis;
    }

    /**
     * 更新交易统计信息
     *
     * @param txnLimitStatis 已经累加的交易统计信息
     * @param limitAcctType  账户类型
     * @param txnNum         交易类型
     * @param transAmt       交易金额
     */
    private void updateTxnLimitStatisInfo(TxnLimitStatis txnLimitStatis, String limitAcctType, String txnNum, String transAmt) {
        txnLimitStatis.setTotalTransAmt("0.00");
        txnLimitStatis.setTotalTransNum(0);
        txnLimitStatis.setCreditTransAmt("0.00");
        txnLimitStatis.setCreditTransNum(0);
        txnLimitStatis.setDebitTransAmt("0.00");
        txnLimitStatis.setDebitTransNum(0);
        txnLimitStatis.setRefundTransAmt("0.00");
        txnLimitStatis.setRefundTransNum(0);
        if (txnNum.substring(1, 3).equals(TransTypeEnum.PAY.getTransType()) || (txnNum.substring(1, 3).equals(TransTypeEnum.AUTH.getTransType()) && "5".equals(txnNum.substring(5, 6)))) {
            /* 支付类及预授权类交易 */
            if (limitAcctType.equals(LimitAcctTypeEnum.ALL.getAcctType())) {
                txnLimitStatis.setTotalTransAmt(transAmt.trim());
                txnLimitStatis.setTotalTransNum(1);
            } else if (limitAcctType.equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                    limitAcctType.equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                    limitAcctType.equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                txnLimitStatis.setCreditTransAmt(transAmt.trim());
                txnLimitStatis.setCreditTransNum(1);
                txnLimitStatis.setTotalTransAmt(transAmt.trim());
                txnLimitStatis.setTotalTransNum(1);
            } else {
                txnLimitStatis.setDebitTransAmt(transAmt.trim());
                txnLimitStatis.setDebitTransNum(1);
                txnLimitStatis.setTotalTransAmt(transAmt.trim());
                txnLimitStatis.setTotalTransNum(1);
            }
        } else if (txnNum.substring(1, 3).equals(TransTypeEnum.REVSAL.getTransType()) || txnNum.substring(1, 3).equals(TransTypeEnum.CANCEL.getTransType()) ||
                (txnNum.substring(1, 3).equals(TransTypeEnum.AUTH.getTransType()) && "6".equals(txnNum.substring(5, 6))) || (txnNum.substring(1, 3).equals(TransTypeEnum.AUTH.getTransType()) && "7".equals(txnNum.substring(5, 6)))) {
            /* 支付冲正、撤销以及预授权的冲正及撤销交易 */
            if (limitAcctType.equals(LimitAcctTypeEnum.ALL.getAcctType())) {
                txnLimitStatis.setTotalTransAmt("-" + transAmt.trim());
                txnLimitStatis.setTotalTransNum(-1);
            } else if (limitAcctType.equals(LimitAcctTypeEnum.CREDIT.getAcctType()) ||
                    limitAcctType.equals(LimitAcctTypeEnum.BANK_CREDIT.getAcctType()) ||
                    limitAcctType.equals(LimitAcctTypeEnum.OTHER_CREDIT.getAcctType())) {
                txnLimitStatis.setCreditTransAmt("-" + transAmt.trim());
                txnLimitStatis.setCreditTransNum(-1);
                txnLimitStatis.setTotalTransAmt("-" + transAmt.trim());
                txnLimitStatis.setTotalTransNum(-1);
            } else {
                txnLimitStatis.setDebitTransAmt("-" + transAmt.trim());
                txnLimitStatis.setDebitTransNum(-1);
                txnLimitStatis.setTotalTransAmt("-" + transAmt.trim());
                txnLimitStatis.setTotalTransNum(-1);
            }
        } else if (txnNum.substring(1, 3).equals(TransTypeEnum.REFUND.getTransType())) {
            /* 退款类交易 */
            txnLimitStatis.setRefundTransAmt(transAmt.trim());
            txnLimitStatis.setRefundTransNum(1);
        } else {
            rglog.info("非支付或者退款交易!");
        }
    }

    /**
     * 获取限额主体日累计及月累计限额统计信息
     *
     * @param instId    多法人标识
     * @param limitInst 限额主体
     * @return 限额统计信息
     * @throws Exception 异常
     */
    private List<TxnLimitStatis> getTxnLimitStatisInfo(String instId, String limitInst) throws Exception {
        String statisDay = DateUtil.getCurrentDate();
        String statisMonth = statisDay.substring(0, 6);
        TxnLimitStatisMapper txnLimitStatisMapper = new TxnLimitStatisMapperImpl();
        List<TxnLimitStatis> txnLimitStatisList = new ArrayList<>();
        /* Step1.1：获取限额主体日限额统计信息 */
        List<TxnLimitStatis> txnDayLimitStatisInfo = txnLimitStatisMapper.selectTxnLimitStatisByLimitInst(instId, statisDay, "D", limitInst);
        if (null != txnDayLimitStatisInfo && !txnDayLimitStatisInfo.isEmpty()) {
            txnLimitStatisList.addAll(txnDayLimitStatisInfo);
        }
        /* Step1.2：获取限额主体月限额统计信息 */
        List<TxnLimitStatis> txnMonthLimitStatisInfo = txnLimitStatisMapper.selectTxnLimitStatisByLimitInst(instId, statisMonth, "M", limitInst);
        if (null != txnMonthLimitStatisInfo && !txnMonthLimitStatisInfo.isEmpty()) {
            txnLimitStatisList.addAll(txnMonthLimitStatisInfo);
        }
        return txnLimitStatisList;
    }

}
